package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.sql.Struct;
import java.util.List;

/**
 * @author atguigu-mqx
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    //  通过软编码的方式获取数据！从配置文件中获取！ 硬编码:
    @Value("${authUrls.url}")
    public String authUrls ; // authUrls = trade.html,myOrder.html,list.html#,#addCart.html

    //  声明一个匹配工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    /**
     *
     * @param exchange 服务器web对象
     * @param chain 过滤器链对象
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //  先获取用户请求路径：
        ServerHttpRequest request = exchange.getRequest();
        //  http://localhost/api/product/inner/getSkuInfo/21
        //  URI uri = request.getURI();
        //  api/product/inner/getSkuInfo/21
        String path = request.getURI().getPath();
        //  判断
        if (antPathMatcher.match("/**/inner/**",path)){
            //  服务器响应
            ServerHttpResponse response = exchange.getResponse();
            //  信息提示
            return outMsg(response, ResultCodeEnum.PERMISSION);
        }
        //  编写一个获取用户Id 方法 userId 在缓存，key
        String userId = this.getUserId(request);
        //  获取临时用户Id
        String userTempId = this.getUserTempId(request);
        if ("-1".equals(userId)){
            //  服务器响应
            ServerHttpResponse response = exchange.getResponse();
            //  信息提示
            return outMsg(response, ResultCodeEnum.PERMISSION);
        }
        //  用户访问带有*/auth/** 接口时，必须要登录！
        if (antPathMatcher.match("/api/**/auth/**",path)){
            //  判断用户是否登录！
            if(StringUtils.isEmpty(userId)){
                //  服务器响应
                ServerHttpResponse response = exchange.getResponse();
                //  信息提示
                return outMsg(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //  用户在访问需要登录的业务模块时，必须要登录！ addToCart.html ,myOrder.html!
        //  判断 用户请求路径中是否包含  {trade.html,myOrder.html,list.html} 中控制器，如果包含，则需要判断用户是否登录！
        //  如果没有登录，则跳转到登录页面！
        String[] split = authUrls.split(",");
        //  判断
        if (split!=null && split.length>0){
            //  循环判断
            for (String url : split) {
                //  path 包含上述url ，并且未登录，则需要跳转到登录页面！ /list.html 是否包含 list.html
                if (path.contains(url) && StringUtils.isEmpty(userId)){
                    //  编写跳转登录页面！
                    //  http://passport.gmall.com/login.html?originUrl=http://www.gmall.com/
                    //  代码...
                    //  获取到响应
                    ServerHttpResponse response = exchange.getResponse();
                    //  设置重定向相关的参数！
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                    //  重定向：
                    return response.setComplete();
                }
            }
        }

        //  判断 , 获取userId 并放入请求头中！ 在登录的时候，已经将用户Id，临时用户Id，使用 js 方式一定放入了header中。
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)){
                //  ServerHttpRequest request
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                //  ServerHttpRequest request
                request.mutate().header("userTempId", userTempId).build();
            }
            //  exchange.mutate().request(ServerHttpRequest request).build();
            //  request ---> exchange
            return chain.filter(exchange.mutate().request(request).build());
        }
        //  默认返回！
        return chain.filter(exchange);
    }

    /**
     * 获取临时用户Id
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {
        //  在cookie 中！
        //  在加入购物车的时候，将临时用户Id 放入了cookie中， 在登录的时候，将临时用户Id 偷偷放入了header中！
        String userTempId = "";
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie!=null){
            userTempId = httpCookie.getValue();
        }else {
            List<String> stringList = request.getHeaders().get("userTempId");
            if (!CollectionUtils.isEmpty(stringList)){
                userTempId = stringList.get(0);
            }
        }
        //  返回数据！
        return userTempId;
    }

    /**
     * 用户信息提示
     * @param response
     * @param resultCodeEnum
     * @return
     */
    private Mono<Void> outMsg(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //  知道输入的信息是什么!
        Result<Object> result = Result.build(null, resultCodeEnum);
        //  将这个result 变为可以输出的数据
        String str = JSON.toJSONString(result);
        //  构建数据流
        DataBuffer wrap = response.bufferFactory().wrap(str.getBytes());
        //  设置一下请求头 Content-type
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //  写数据.
        return response.writeWith(Mono.just(wrap));
    }

    /**
     * 获取用户Id
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {
        //  获取用户Id ： redis
        //  必须先获取到token
        //  获取token --- cookie ，header中 从header中！
        String token = "";
        List<String> stringList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(stringList)){
            token = stringList.get(0);
        }else {
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if (httpCookie!=null){
                token = httpCookie.getValue();
            }
        }
        //  判断
        if(!StringUtils.isEmpty(token)){
            //  缓存key
            String loginKey = "user:login:"+token;
            String strJson = (String) redisTemplate.opsForValue().get(loginKey);
            JSONObject jsonObject = JSONObject.parseObject(strJson);
            String ip = (String) jsonObject.get("ip");
            if (ip.equals(IpUtil.getGatwayIpAddress(request))){
                //  判断ip 地址是否一样！
                String userId = (String) jsonObject.get("userId");
                return userId;
            }else {
                return "-1";
            }
        }
        //  返回空字符串！
        return "";
    }



    //    public static void main(String[] args) {
    //        String authUrls = "trade.html,myOrder.html,list.html";
    //        String[] split = authUrls.split(",");
    //        String path = "http://list.gmall.com/myOrder.html?category3Id=61";
    //        for (String url : split) {
    //            //  path 包含上述url ，并且未登录，则需要跳转到登录页面！
    //            if (path.contains(url) ){
    //                System.out.println("来人了， 开始接客了.");
    //            }
    //        }
    //    }
}
